/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "GPKArchiveManager.h"

#include "DataSerializer.h"
#include "GPKArchive.h"
#include "NativeFile.h"
#include "DataSerializer.h"

using namespace PQCore;
namespace PQEngine
{
	const std::string GPKArchiveManager::PERSIS_FILE_NAME="Assets.gdt";

	GPKArchiveManager::GPKArchiveManager()
		: _inited(false)
	{

	}

	void GPKArchiveManager::init(std::string path)
	{
		if(_inited){
			return;
		}
		
		_path=path;
		std::string fullName=_path+"/";
		fullName+=PERSIS_FILE_NAME;

		//init archives using data in GAssets.gdt
		SerializeParser parser(fullName);
		if(!parser.success()){
			_inited=true;
			return;
		}

		SerializeDataId gname=parser.getName();
		if(gname==SerializeDataId_AssetsArchive){
			int size=parser.getParam()->getInt();
			for(int i=0;i<size;i++){
				_archivePathes.push_back(parser.getParam()->getString());
			}
		}

		_inited=true;
	}


	GPKArchiveManager& GPKArchiveManager::getSingleton()
	{
		static GPKArchiveManager inst;
		return inst;
	}

	bool GPKArchiveManager::hasArchive(std::string name)
	{
		assert(_inited);

		std::string path=_path+"/";
		path+=name;
		path+=".";
		path+=GPKArchive::EXT_GPK;

		int size=_archivePathes.size();
		for(int i=0;i<size;i++){
			if(_archivePathes[i]==path){
				return true;
			}
		}

		return false;
	}


	GPKArchive* GPKArchiveManager::createArchive(std::string name)
	{
		assert(_inited);

		std::string path=_path+"/";
		path+=name;
		path+=".";
		path+=GPKArchive::EXT_GPK;

		int size=_archivePathes.size();
		for(int i=0;i<size;i++){
			if(_archivePathes[i]==path){
				return 0;//already have
			}
		}

		GPKArchive* archive=GPKArchive::get(path);
		if(!archive){
			return 0;//shouldn't reach here?
		}

		_archivePathes.push_back(path);
		
		persist();//persist to file
		return archive;
	}

	void GPKArchiveManager::persist()
	{
		assert(_inited);

		SerializeGenerator gen(SerializeDataId_AssetsArchive);
		int size=_archivePathes.size();
		gen.addIntParam(size);
		for(int i=0;i<size;i++){
			gen.addStringParam(_archivePathes[i]);
		}

		std::string name=_path+"/";
		name+=PERSIS_FILE_NAME;
		gen.serialize(name);

	}

	std::string GPKArchiveManager::getArchiveName(int index)
	{
		assert(_inited);
		assert(index>=0&&index<_archivePathes.size());
		std::string path= _archivePathes[index];
		int pos=path.find_last_of("/");
		int pos1=path.find_last_of(".");
		int len=pos1-pos-1;
		std::string name=path.substr(pos+1,len);
		return name;
		
	}

	bool GPKArchiveManager::addArchiveFile(int index,std::string fileName)
	{
		assert(_inited);
		if(index>=0&&index<_archivePathes.size()){
			std::string archivePath=_archivePathes[index];
			GPKArchive* archive=GPKArchive::get(archivePath);
			return archive->addFile(fileName);
		}
		return false;
	}

	bool GPKArchiveManager::addArchiveFile(std::string name,std::string filePath)
	{
		assert(_inited);
		if(!hasArchive(name)){
			return false;
		}
		
		std::string path=_path+"/";
		path+=name;
		path+=".";
		path+=GPKArchive::EXT_GPK;

		GPKArchive* archive=GPKArchive::get(path);
		if(archive){
			return archive->addFile(filePath);
		}
		return false;
		
	}

	int GPKArchiveManager::getNumFile(int index)
	{
		assert(_inited);
		assert(index>=0&&index<_archivePathes.size());
		std::string archivePath=_archivePathes[index];
		GPKArchive* archive=GPKArchive::get(archivePath);
		return archive->getNumFile();
	}

	std::string GPKArchiveManager::getFileName(int archiveIndex,int fileIndex)
	{
		assert(_inited);
		assert(archiveIndex>=0&&archiveIndex<_archivePathes.size());
		std::string archivePath=_archivePathes[archiveIndex];
		GPKArchive* archive=GPKArchive::get(archivePath);
		return archive->getFileName(fileIndex);
		
	}

	GPKFile* GPKArchiveManager::getFile(std::string path)
	{
		assert(_inited);
		std::string archiveName=FileSystem::getPathFirstNode(path);//with ext
		std::string filePath=FileSystem::removeFirstNode(path);
		GPKArchive* archive=getArchive(archiveName);
		if(archive){
			return archive->getFile(filePath);
		}

		return 0;
	}

	bool GPKArchiveManager::hasFile(std::string path)
	{
		assert(_inited);
		std::string archiveName=FileSystem::getPathFirstNode(path);
		std::string filePath=FileSystem::removeFirstNode(path);
		GPKArchive* archive=getArchive(archiveName);
		if(archive){
			return archive->hasFile(filePath);
		}

		return false;
	}
	
	GPKArchive* GPKArchiveManager::getArchive(std::string archiveName)
	{
		assert(_inited);
		int size=_archivePathes.size();
		for(int i=0;i<size;i++){
			std::string path= _archivePathes[i];
			
			int pos=path.find_last_of("/");
			int pos1=path.find_last_of(".");
			int len=pos1-pos-1;
			std::string name=path.substr(pos+1,len);
			if(name==archiveName){
				return GPKArchive::get(path);
			}
		}
		
		return 0;	
	}

}
